package it.tukano.treditor.modules;

import it.tukano.app.AbstractAppModule;
import it.tukano.app.AppModule;
import it.tukano.check.Todo;
import it.tukano.swingdeco.containers.JPanelExt;
import it.tukano.swingdeco.containers.JRowPanel;
import it.tukano.treditor.engine.geom.EulerSet;
import it.tukano.treditor.engine.geom.NTuple3;
import it.tukano.treditor.engine.scene.ModelElement;
import it.tukano.treditor.engine.scene.SceneElement;
import it.tukano.treditor.modules.datamodel.DataModelEvent;
import it.tukano.treditor.modules.datamodel.DataModelListener;
import it.tukano.treditor.resources.Labels;
import it.tukano.treditor.resources.Labels.LabelKey;
import it.tukano.treditor.ui.EulerSetEditor;
import it.tukano.treditor.ui.Tuple3nEditor;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;

/**
 * Display for the properties of a model
 * @author pgi
 */
public class ModelPropertiesForm extends AbstractAppModule implements DataModelListener {
    private ModelElement model;
    private Tuple3nEditor translationEditor = new Tuple3nEditor(
            Labels.getInstance().getLabelValue(LabelKey.POSX),
            Labels.getInstance().getLabelValue(LabelKey.POSY),
            Labels.getInstance().getLabelValue(LabelKey.POSZ),
            0.1);
    private Tuple3nEditor scaleEditor = new Tuple3nEditor(
            Labels.getInstance().getLabelValue(LabelKey.SCALEX),
            Labels.getInstance().getLabelValue(LabelKey.SCALEY),
            Labels.getInstance().getLabelValue(LabelKey.SCALEZ),
            0.1);
    private EulerSetEditor rotationEditor = new EulerSetEditor(
            Labels.getInstance().getLabelValue(LabelKey.ROTX),
            Labels.getInstance().getLabelValue(LabelKey.ROTY),
            Labels.getInstance().getLabelValue(LabelKey.ROTZ),
            5.0);
    private JRowPanel editor = JRowPanel.newTopAlignedInstance()
            .addRow(translationEditor)
            .addRow(rotationEditor)
            .addRow(scaleEditor);
    private JPanelExt form = new JPanelExt(new BorderLayout())
            .append(new JScrollPane(editor), BorderLayout.CENTER)
            .withName(Labels.getInstance().getLabelValue(LabelKey.MODEL_FORM_TITLE));
    private final Runnable editorsListener = new Runnable() {

        public void run() {
            ModelPropertiesForm.this.doUpdateModelTransform();
        }
    };
    private DataModel dataModel;

    /**
     * Instance initializer
     */
    public ModelPropertiesForm() {
        translationEditor.setTitledBorder(Labels.getInstance().getLabelValue(LabelKey.POSITION));
        rotationEditor.setTitledBorder(Labels.getInstance().getLabelValue(LabelKey.ROTATION));
        scaleEditor.setTitledBorder(Labels.getInstance().getLabelValue(LabelKey.SCALE));
        translationEditor.addListener(editorsListener);
        rotationEditor.addListener(editorsListener);
        scaleEditor.addListener(editorsListener);
    }

    @Override
    public void startModule(AppModule context) {
        this.dataModel = find(DataModel.class);
        dataModel.addListener(this);
    }

    public void dataModelEventPerformed(DataModelEvent e) {
        if(e.getEventSource() == this) return;
        
        switch(e.getType()) {
            case SELECTED_ELEMENT_SET:
                handleSelectedElementSet(e);
                break;
            case MODEL_TRANSFORM_UPDATE:
                final ModelElement updatedModel = e.getArg(0, ModelElement.class);
                updateEditorTransformIfNeeded(updatedModel);
                break;
        }
    }

    protected void handleSelectedElementSet(DataModelEvent e) {
        final int argCount = e.getArgumentCount();
        if(argCount == 0) {
            hideFormIfVisible();
        } else {
            final SceneElement selectedElement = e.getArg(0, SceneElement.class);
            if(selectedElement.getType() == SceneElement.Type.MODEL) {
                final ModelElement currentModel = (ModelElement) selectedElement;
                setModel(currentModel);
                showFormIfHidden();
            } else {
                hideFormIfVisible();
            }
        }
    }

    protected void setModel(ModelElement model) {
        this.model = model;
        scaleEditor.setEditedValue(model.getLocalScale());
        translationEditor.setEditedValue(model.getLocalTranslation());
        rotationEditor.setEditedValue(model.getLocalRotation());
    }

    protected void hideFormIfVisible() {
        if(form.isShowing()) {
            find(MainFrame.class).uninstall(form);
        }
    }

    protected void showFormIfHidden() {
        if(!form.isShowing()) {
            find(MainFrame.class).install(form, BorderLayout.EAST, true);
        }
    }

    protected void doUpdateModelTransform() {
        NTuple3 scale = scaleEditor.getEditedValue();
        EulerSet rotation = rotationEditor.getEditedValue();
        NTuple3 translation = translationEditor.getEditedValue();
        model.setLocalRotation(rotation);
        model.setLocalScale(scale);
        model.setLocalTranslation(translation);
        dataModel.notifyModelTransformUpdate(this, model);
    }

    protected void updateEditorTransformIfNeeded(ModelElement updatedModel) {
        if(updatedModel == model) {
            scaleEditor.setEditedValue(updatedModel.getLocalScale());
            translationEditor.setEditedValue(updatedModel.getLocalTranslation());
            rotationEditor.setEditedValue(updatedModel.getLocalRotation().toDegrees());
        }
    }
}
